use crate::phi::data::Rectangle;
use sdl2::image::LoadTexture;
use sdl2::render::{Renderer, Texture, TextureQuery};
use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;

#[derive(Clone)]
pub struct Sprite {
    tex: Rc<RefCell<Texture>>,
    src: Rectangle,
}

impl Sprite {
    pub fn size(&self) -> (f64, f64) {
        (self.src.w, self.src.h)
    }

    pub fn new(texture: Texture) -> Self {
        let TextureQuery { width, height, .. } = texture.query();
        Self {
            tex: Rc::new(RefCell::new(texture)),
            src: Rectangle {
                w: width as f64,
                h: height as f64,
                x: 0.0,
                y: 0.0,
            },
        }
    }

    pub fn load(canvas: &Renderer, path: &str) -> Option<Sprite> {
        canvas.load_texture(Path::new(path)).ok().map(Sprite::new)
    }

    pub fn region(&self, rect: Rectangle) -> Option<Sprite> {
        let src: Rectangle = Rectangle {
            x: rect.x + self.src.x,
            y: rect.y + self.src.y,
            ..rect
        };
        if self.src.contains(src) {
            Some(Sprite {
                tex: self.tex.clone(),
                src,
            })
        } else {
            None
        }
    }

    pub fn render(&self, canvas: &mut Renderer, dest: Rectangle) {
        canvas
            .copy(&mut self.tex.borrow_mut(), self.src.to_sdl(), dest.to_sdl())
            .expect("failed to copy texture");
    }
}

pub trait CopySprite {
    fn copy_sprite(&mut self, sprite: &Sprite, dest: Rectangle);
}

impl<'window> CopySprite for Renderer<'window> {
    fn copy_sprite(&mut self, sprite: &Sprite, dest: Rectangle) {
        sprite.render(self, dest);
    }
}
